//
//							Misc.h
//

#ifndef __NEWA_MISC_H
#define __NEWA_MISC_H

#pragma message( "INCLUDING FILE: " __FILE__ )

#include <algorithm>

namespace newa
{
	struct Point
	{
		int x, y;

		Point( int _x = 0, int _y = 0 )
			: x( _x ), y( _y )
		{}

		Point relativeTo( const Point& p ) const
		{
			return Point( x - p.x, y - p.y );
		}

		Point fromBase( const Point& p ) const
		{
			return Point( x + p.x, y + p.y );
		}
	};
	
	struct Size
	{
		int width, height;

		Size( int _w, int _h )
			: width ( _w ), height ( _h )
		{}
	};
	
	struct Rect
	{
		int x, y;
		int width, height;

		Rect()
			: x( 0 ), y( 0 ), width( 0 ), height( 0 )
		{}

		Rect( int w, int h )
			: x( 0 ), y( 0 ), width( w ), height( h )
		{}

		Rect( int _x, int _y, int _w, int _h )
			: x( _x ), y( _y ), width( _w ), height( _h )
		{}

		Rect( const Size& sz )
			: x( 0 ), y( 0 ), width( sz.width ), height( sz.height )
		{}

		Rect( const Point& p, const Size& sz )
			: x( p.x ), y( p.y ), width( sz.width ), height( sz.height )
		{}

		Point pos() const
		{
			return Point( x, y );
		}

		Size size() const
		{
			return Size( width, height );
		}

		bool contains( int _x, int _y ) const
		{
			return x <= _x && _x < x + width
				&& y <= _y && _y < y + height;
		}

		bool contains( Point p ) const
		{
			return contains( p.x, p.y );
		}

		bool empty() const
		{
			return width <= 0 || height <= 0;
		}

		Rect intersection( const Rect& r ) const
		{
			int nx = std::max( x, r.x );
			int ny = std::max( y, r.y );
			int nw = std::min( x + width, r.x + r.width ) - nx;
			int nh = std::min( y + height, r.y + r.height ) - ny;

			return Rect( nx, ny, nw, nh );
		}

		void inflate( int dx, int dy )
		{
			x -= dx;
			y -= dy;
			width += 2 * dx;
			height += 2 * dy;
		}

		void deflate( int dx, int dy )
		{
			inflate( -dx, -dy );
		}

		void inflate( int d )
		{
			inflate( d, d );
		}

		void deflate( int d )
		{
			inflate( -d );
		}
	};

	inline bool operator == ( const Rect& r1, const Rect& r2 )
	{
		return r1.x == r2.x 
			&& r1.y == r2.y
			&& r1.width == r2.width
			&& r1.height == r2.height;
	}

	inline bool operator != ( const Rect& r1, const Rect& r2 )
	{
		return !( r1 == r2 );
	}

	inline Rect operator + ( const Rect& r, const Point& p )
	{
		return Rect( r.x + p.x, r.y + p.y, r.width, r.height );
	}

	inline Rect operator - ( const Rect& r, const Point& p )
	{
		return Rect( r.x - p.x, r.y - p.y, r.width, r.height );
	}

	inline Rect CombineRects( const Rect& r1, const Rect& r2 )
	{
		Rect r;

		r.x = std::min( r1.x, r2.x );
		r.y = std::min( r1.y, r2.y );

		int right = std::max( r1.x + r1.width, r2.x + r2.width );
		int bottom = std::max( r1.y + r1.height, r2.y + r2.height );

		r.width = right - r.x;
		r.height = bottom - r.y;

		return r;
	}

	template< typename Item >
	void MoveItemRectTo( Item& item, int x, int y )
	{
		Rect r = item.rect();

		r.x = x;
		r.y = y;

		item.rect( r );
	}

	template< typename Item >
	void MoveItemRectRel( Item& item, int dx, int dy )
	{
		Rect r = item.rect();

		r.x += dx;
		r.y += dy;

		item.rect( r );
	}
}

#endif
